﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using InformationExtraction.Common;
using InformationExtraction.Interface;
using System.IO;
using System.Text.RegularExpressions;

namespace InformationExtraction.Utils
{
    //ww
    public class LocationExtracter : IFeatureExtractable
    {
        private Dictionary<string, string> CountryName;
        private Dictionary<string, string> CityName;
        private Dictionary<string, string> ProvinceName;

        private string currentProcessTokenContent;

        private bool isInFrontOfDoc = true;

        private int lastPreLineNum = -1;
        private int lastCurrentLineNum = -1;
        private int lastNextLineNum = -1;

        private bool isPreLineSat = false;
        private bool isCurrentLineSat = false;
        private bool isNextLineSat = false;


        public LocationExtracter()
        {
            Initialization();
        }

        #region IFeatureExtractable 成员

        List<int> IFeatureExtractable.Extract(Token token)
        {
            List<int> result = new List<int>();

            currentProcessTokenContent = TokenContentPrePreocession(token);
            isInFrontOfDoc = IsInFrontOfDoc(token);

            if (token.InLine != null)
            {

                if (token.InLine.No != lastCurrentLineNum)
                {
                    lastCurrentLineNum = token.InLine.No;
                    isCurrentLineSat = HasDate(token.InLine.RawContent) || HasSpecialCurrentLineWord(token.InLine.RawContent);
                }
            }

            if (token.InLine.PriorLine != null)
            {
                if (token.InLine.PriorLine.No != lastPreLineNum)
                {
                    lastPreLineNum = token.InLine.PriorLine.No;
                    isPreLineSat = HasDate(token.InLine.PriorLine.RawContent) || HasSpecialPreLineWord(token.InLine.PriorLine.RawContent);
                }
            }

            if (token.InLine.NextLine != null)
            {
                if (token.InLine.NextLine.No != lastNextLineNum)
                {
                    lastNextLineNum = token.InLine.NextLine.No;
                    isNextLineSat = HasDate(token.InLine.NextLine.RawContent) || HasSpecialNextLineWord(token.InLine.NextLine.RawContent);
                }
            }

            result.Add(LocationFeature_1(token));
            result.Add(LocationFeature_2(token));
            result.Add(LocationFeature_3(token));
            result.Add(LocationFeature_4(token));
            result.Add(LocationFeature_5(token));
            result.Add(LocationFeature_6(token));
            result.Add(LocationFeature_7(token));

            return result;
        }

        InformationType IFeatureExtractable.GetTargetType()
        {
            return InformationType.Location;
        }

        #endregion Extract Features

        #region Location Feature Extraction
        /// <summary>
        /// 是否是地名（国家、省份、城市，全名，缩写。。。）
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private int LocationFeature_1(Token token)
        {
            if (isInFrontOfDoc)
            {
                string tokencontent = currentProcessTokenContent;

                if (IsInNameDictionary(tokencontent))
                    return 1;
                else
                    return -1;
            }

            return -1;
        }

        /// <summary>
        /// 和前面一个词加一起出现在词典中
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private int LocationFeature_2(Token token)
        {

            if (isInFrontOfDoc)
            {
                string currentName = currentProcessTokenContent;
                string combineName = "";

                if (token.Prior != null)
                {
                    string priorName = TokenContentPrePreocession(token.Prior);
                    combineName = priorName + " " + currentName;

                    if (IsInNameDictionary(combineName))
                        return 1;
                }
            }
            return -1;
        }

        /// <summary>
        /// 和后面一个词加一起出现在词典中
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private int LocationFeature_3(Token token)
        {
            if (isInFrontOfDoc)
            {
                string currentName = currentProcessTokenContent;
                string combineName = "";

                if (token.Next != null)
                {
                    string nextName = TokenContentPrePreocession(token.Next);
                    combineName = currentName + " " + nextName;

                    if (IsInNameDictionary(combineName))
                        return 1;
                }
            }
            return -1;
        }

        /// <summary>
        /// 用/隔开的两个地点特别判断
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private int LocationFeature_4(Token token)
        {
            if (token.Type == InformationType.Location)
            {
                int temp = 0;
            }

            if (isInFrontOfDoc)
            {
                string[] names = currentProcessTokenContent.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries);

                if (names.Length > 1)
                {
                    if (IsInNameDictionary(names[0]) || IsInNameDictionary(names[1]))
                        return 1;
                    else return -1;
                }
            }
            return -1;
        }

        /// <summary>
        /// 所在行有表示时间的单词或者其他特殊的词
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private int LocationFeature_5(Token token)
        {
            if (token.InLine != null && token.InLine.RawContent != null)
            {
                if (isCurrentLineSat)
                    return 1;
            }


            return -1;
        }

        /// <summary>
        /// 上一行 有表示时间的单词或者其他特殊的词
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private int LocationFeature_6(Token token)
        {
            if (token.InLine != null && token.InLine.PriorLine != null && token.InLine.PriorLine.RawContent != null)
            {
                string priContent = token.InLine.PriorLine.RawContent;
                //if (HasDate(priContent) || HasSpecialPreLineWord(priContent))
                if (isPreLineSat)
                {
                    return 1;
                }
            }
            return -1;
        }

        /// <summary>
        /// 下一行 有表示时间的单词或者其他特殊的词
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private int LocationFeature_7(Token token)
        {
            if (token.InLine != null && token.InLine.NextLine != null && token.InLine.NextLine.RawContent != null)
            {
                string nextContent = token.InLine.NextLine.RawContent;

                if (isNextLineSat)
                {
                    return 1;
                }
            }

            return -1;
        }
        #endregion

        #region Util Function
        private void Initialization()
        {
            CountryName = new Dictionary<string, string>();
            ProvinceName = new Dictionary<string, string>();
            CityName = new Dictionary<string, string>();

            using (StreamReader sr_country = new StreamReader("Utils/country_name.txt"))
            {
                string line = sr_country.ReadLine();
                while (line != null)
                {
                    if (!CountryName.ContainsKey(line))
                        CountryName.Add(line, line);
                    line = sr_country.ReadLine();
                }
            }

            using (StreamReader sr_province = new StreamReader("Utils/province_name.txt"))
            {
                string line = sr_province.ReadLine();
                while (line != null)
                {
                    if (!ProvinceName.ContainsKey(line))
                        ProvinceName.Add(line, line);
                    line = sr_province.ReadLine();
                }
            }

            using (StreamReader sr_city = new StreamReader("Utils/city_name.txt"))
            {
                string line = sr_city.ReadLine();
                while (line != null)
                {
                    if (!CityName.ContainsKey(line))
                        CityName.Add(line, line);
                    line = sr_city.ReadLine();
                }
            }
        }

        private string TokenContentPrePreocession(Token token)
        {
            string result = token.Content;
            //逗号，括号要去掉
            result = result.Replace(",", "");
            result = result.Replace("(", "");
            result = result.Replace(")", "");

            //单词长度大于4的，第一个字母大写，其他字母小写
            if (result.Length > 3)
            {
                char[] newOnes = new char[result.Length];

                for (int i = 0; i < result.Length; i++)
                {
                    if (i == 0)
                    {
                        newOnes[i] = Char.ToUpper(result[i]);
                    }
                    else
                    {
                        newOnes[i] = Char.ToLower(result[i]);
                    }
                }
                result = new string(newOnes);
            }

            return result;
        }

        private bool IsInFrontOfDoc(Token token)
        {
            double position = token.InLine.No * 1.0 / token.InLine.InDocument.LineCount * 1.0;

            if (position <= 0.5)
                return true;
            else return false;
        }

        private bool HasDate(string content)
        {
            Regex r = new Regex("(.*)(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sept|Oct|Nov|Dec)(.*)");
            Match m = r.Match(content);

            if (m.Success)
            {
                return true;
            }
            return false;
        }

        private bool HasSpecialCurrentLineWord(string content)
        {
            Regex r = new Regex("(.*)(Location|location|located|workshops|Workshop|workshop|held in|held|takes place on|meeting|In connection with|" +
             "in conjunction with|Place|WHERE|Where|place on)(.*)", RegexOptions.IgnoreCase);
            Match m = r.Match(content);

            if (m.Success)
            {
                return true;
            }
            return false;
        }

        private bool HasSpecialPreLineWord(string content)
        {
            Regex r = new Regex("(.*)(Conference|conference|CONFERENCE|conferences|workshops|Workshop|workshop|held in|held|" +
             "symposium|Symposium|SYMPOSIUM|)(.*)", RegexOptions.IgnoreCase);
            Match m = r.Match(content);

            if (m.Success)
            {
                return true;
            }
            return false;
        }

        private bool HasSpecialNextLineWord(string content)
        {
            Regex r = new Regex("(.*)(Conference|conference|CONFERENCE|conferences|workshops|Workshop|workshop|held in|held|" +
 "symposium|Symposium|SYMPOSIUM|http://|SPOSNORS|SPONSORED|sponsored|website)(.*)", RegexOptions.IgnoreCase);
            Match m = r.Match(content);

            if (m.Success)
            {
                return true;
            }

            r = new Regex("(.*)[A-Z](&apos;| &apos;|&apos; | )?[0-9]");

            m = r.Match(content);
            if (m.Success)
                return true;

            return false;
        }

        private bool IsInNameDictionary(string name)
        {
            if (CountryName.ContainsKey(name) || ProvinceName.ContainsKey(name) || CityName.ContainsKey(name))
            {
                return true;
            }
            else
                return false;
        }
        #endregion
    }
}
